package com.rtsffm.rtd.action.registry;

import java.lang.reflect.Method;

import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

//~--- classes ----------------------------------------------------------------

public class PChainExecution implements PExecution {
    private final List<Entry<String, Class<?>>> actionChain;
    private final Map<String, Class<?>>         actionChainMap;
    private final Method                        declaredChainMethod;
    private final Map<String, PExecution>       execMap;
    private PExecution                          finalCall;

    //~--- constructors -------------------------------------------------------

    public PChainExecution(Method declChainMtd) {
        declaredChainMethod = declChainMtd;
        actionChainMap      = new LinkedHashMap<String, Class<?>>();
        execMap             = new HashMap<String, PExecution>();
        actionChain         = new ArrayList<Map.Entry<String, Class<?>>>();
    }

    //~--- methods ------------------------------------------------------------

    @Override
    public boolean execute(Object invoker, Object cause, Object context, Object... delegates) {
        if (delegates == null) {
            return false;
        }

        Map<Class<?>, Set<Object>> delegateListByClass = new HashMap<Class<?>, Set<Object>>();
        List<Object>               delegateList        = new ArrayList<Object>(Arrays.asList(delegates));

        delegateList.add(invoker);

        for (Object obj : delegateList) {
            Set<Object> existingList;

            if ((existingList = delegateListByClass.get(obj.getClass())) == null) {
                delegateListByClass.put(obj.getClass(), existingList = new HashSet<Object>());
            }

            existingList.add(obj);
        }

        if (!delegateListByClass.keySet().containsAll(actionChainMap.values())) {
            return false;
        }

        for (Entry<String, Class<?>> entry : actionChain) {}

        finalCall.execute(invoker, cause, context);

        return false;
    }

    @Override
    public void addNextExecution(PExecution next) {}

    public void addToChain(String actionId, Class<?> declaringClass, PExecution exec) {
        actionChainMap.put(actionId, declaringClass);
        execMap.put(actionId, exec);
        actionChain.add(new AbstractMap.SimpleImmutableEntry<String, Class<?>>(actionId, declaringClass));
    }

    public void done() {
        finalCall = new PSingleExecution(declaredChainMethod);
    }
}
